<?php

/**
 * 日志类
 */
class Logger {

    protected static $_instance = NULL;
    private static $time_arr = array();

    protected function __construct() {
        
    }

    /**
     * 单例模式
     * @return Logger
     */
    public static function getInstance() {
        if (null === self::$_instance) {
            self::$_instance = new self();
        }
        return self::$_instance;
    }

    /**
     * 开始记录请求
     * @param string $tag 请求标识
     * @param boolean $log 是否写入日志
     * @return string
     */
    public function start($tag = 'default', $log = FALSE) {
        $microtime = microtime(TRUE);
        self::$time_arr[$tag] = $microtime;
        if ($log) {
            self::getInstance()->log("Logger started", 'debug');
        }
        return array('microtime' => $microtime);
    }

    /**
     * 终止记录请求
     * @param string $tag 请求标识
     * @param boolean $log 是否写入日志
     * @return array
     */
    public function stop($tag = 'default', $log = FALSE) {
        $microtime = microtime(TRUE);
        $mempeakusage = Tools::formatBytes(memory_get_peak_usage(TRUE));
        $memusage = Tools::formatBytes(memory_get_usage(TRUE));
        self::$time_arr[$tag] = isset(self::$time_arr[$tag]) ? self::$time_arr[$tag] : STARTTIME;
        $microtimeused = number_format(($microtime - self::$time_arr[$tag]), 4) . ' s';
        if ($log) {
            $buffer = "Logger completed in " . $microtimeused . "ms | mem usage: (" . $memusage . ") | mem peak usage: (" . $mempeakusage . ")";
            self::getInstance()->log($buffer, 'debug');
        }
        return array('microtime' => $microtime, 'microtimeused' => $microtimeused, 'mempeakusage' => $mempeakusage, 'memusage' => $memusage);
    }

    /**
     * 记录SQL查询语句
     * @param string $query
     * @param string $class_name
     * @param float $parse_time
     */
    public function sql($query, $class_name = NULL, $parse_time = 0) {
        $class_name = $class_name ? : 'Sql';
        $buffer = "$class_name (" . number_format($parse_time * 1000) . "ms)  " . $query;
        self::getInstance()->log($buffer, 'sql');
    }

    /**
     * 记录日志信息
     * @param string $text 日志内容
     * @param string $type 日志类型
     */
    public function log($text, $type = 'log') {
        $filepath = Yaf_Registry::get('config')->logger->directory . '/' . $type . '.' . date("Y-m-d") . '.' . Yaf_Registry::get('config')->logger->ext;
        if (!$fp = @fopen($filepath, 'a')) {
            return FALSE;
        }
        flock($fp, LOCK_EX);

        $repeatnums = 8 - strlen($type);
        fwrite($fp, date('Y-m-d H:i:s') . ' - ' . $type . ($repeatnums > 0 ? str_repeat(' ', $repeatnums) : '') . '--> ' . $text . "\r\n");

        flock($fp, LOCK_UN);
        fclose($fp);
        return TRUE;
    }

    /**
     * 记录错误信息
     * @param mixed $exception
     */
    public function error($exception, $render = FALSE) {
        if (is_array($exception)) {
            extract($exception);
        } else if (is_object($exception)) {
            $code = $exception->getCode();
            $message = $exception->getMessage();
            $file = $exception->getFile();
            $line = $exception->getLine();
        } else {
            $e = error_get_last();
            if (is_array($e))
                extract($e);
        }
        if (isset($message)) {
            self::log($message . ' -> ' . $file . ' -> ' . $line . ' -> ' . $code . ' -> ' . Yaf_Dispatcher::getInstance()->getRequest()->getServer('REQUEST_URI'), 'error');
            if ($render) {
                $error = array('code' => $code, 'message' => $message, 'file' => $file, 'line' => $line);
                //先从module中找view目录
                $view = new Yaf_View_Simple(is_dir(VIEW_PATH . '/error/') ? VIEW_PATH : APPLICATION_PATH . '/views/');
                $view->assign("site", Yaf_Registry::get("config")->site->toArray());
                $view->display('error/' . YAF_ENVIRON . '.phtml', $error);
            }
        }
    }

    /**
     * 记录请求的所有数据,含POST/GET信息
     */
    public function request($type = 'error') {
        $text = '';
        $request = Yaf_Dispatcher::getInstance()->getRequest();
        if ($request->isXmlHttpRequest()) {
            $text = ' -> XML -> ' . http_build_query(json_decode(json_encode(simplexml_load_string(file_get_contents('php://input'))), TRUE));
        } else if ($request->isPost()) {
            $text = ' -> POST -> ' . ($request->getPost() ? http_build_query($request->getPost()) : file_get_contents('php://input'));
        } else {
            
        }
        $text .= ($request->getQuery() ? ' -> GET -> ' . http_build_query($request->getQuery()) : '');
        self::log($request->getRequestUri() . $text . ' -> IP -> ' . Tools::getRemoteAddr(), $type);
    }

    /**
     * 错误捕获处理
     * @param int $errno
     * @param string $errstr
     * @param string $errfile
     * @param int $errline
     */
    public function error_handler($errno, $errstr, $errfile, $errline) {
        switch ($errno) {
            case YAF_ERR_NOTFOUND_MODULE:
            case YAF_ERR_NOTFOUND_CONTROLLER:
            case YAF_ERR_NOTFOUND_ACTION:
            case YAF_ERR_NOTFOUND_VIEW:
            default :
                break;
        }
        $error = array('code' => $errno, 'message' => $errstr, 'file' => $errfile, 'line' => $errline);
        self::error($error, TRUE);
    }

    /**
     * 程序意外终止
     */
    public function shutdown_handler() {
        if ($e = error_get_last()) {
            //严重错误提示
            self::error_handler($e['type'], $e['message'], $e['file'], $e['line']);
        }
    }

}
